package com.gatico;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class NettyServer {
    private static Logger logger = LoggerFactory.getLogger(NettyServer.class);

    private static Integer port = 10000;
    Map<String, String> ipMap = new HashMap<>();

    static Map<InetSocketAddress, SocketChannel> socketChannelMap = new HashMap<>();

    public void run() throws Exception {
        // 创建两个EventLoopGroup，bossGroup用于接收客户端的连接，workerGroup用于处理已接收的连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 创建ServerBootstrap实例，用于启动服务端
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务端的通道实现
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 添加一个ChannelInitializer用于配置新的Channel
                        @Override
                        public void initChannel(SocketChannel ch) {
                            // 设置读写空闲时间为5秒
                            ch.pipeline().addLast(new IdleStateHandler(5, 5, 0));
                            ch.pipeline().addLast(new ProxyDecoder(), new ProxyEncoder(), new ServerHandler());
//                            ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 16, 4, 0, 16));
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)          // 设置线程队列得到的连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置保持活动连接状态

            // 绑定端口并启动服务端
            ChannelFuture f = b.bind("0.0.0.0", port).sync();

            // 等待服务端Socket关闭
            f.channel().closeFuture().sync();
        } finally {
            // 优雅地关闭两个EventLoopGroup
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    static Map<Integer, ProxyServer> integerProxyServerMap = new ConcurrentHashMap<>();
    static Map<ChannelHandlerContext, Integer> contextIntegerMap = new ConcurrentHashMap<>();

    // 服务端处理器
    private static class ServerHandler extends ChannelInboundHandlerAdapter {
        public void channelActive(ChannelHandlerContext ctx) {
            // 当连接建立时，发送消息到服务器
            System.out.println("收到客户端的连接");
            ctx.writeAndFlush(ProxyProtocol.msgProtocol("你好，客户端！"));
        }

        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ProxyProtocol protocol = (ProxyProtocol) msg;
            if (protocol.type == ProxyProtocol.TYPE.HEART.value()) {
                // 心跳
                System.out.println("收到客户端心跳");
            } else if (protocol.type == ProxyProtocol.TYPE.TCP.value()) {
                // tcp代理
                System.out.println("收到客户端数据，需要进行tcp代理:");
            } else if (protocol.type == ProxyProtocol.TYPE.HTTP.value()) {
                // http代理
                System.out.println("收到浏览器数据，需要进行http代理:");
                System.out.println("收到浏览器消息:" + new String(protocol.data));
                integerProxyServerMap.get(contextIntegerMap.get(ctx)).onRead(protocol);
            } else if (protocol.type == ProxyProtocol.TYPE.MSG.value()) {
                // 消息
                System.out.println("收到客户端消息:" + new String(protocol.data));
                String jsonStr = new String(protocol.data);
                JSONObject json = JSON.parseObject(jsonStr);
                if (json.get("type").equals("init")) {
                    int id = json.getInteger("id");
                    String ip = json.getString("ip");
                    int port = json.getInteger("port");
                    if (!integerProxyServerMap.containsKey(id)) {
                        ProxyServer proxyServer = new ProxyServer(id, ctx);
                        proxyServer.setProxyIp(ip);
                        proxyServer.setProxyPort(port);
                        proxyServer.start();
                        integerProxyServerMap.put(id, proxyServer);
                        contextIntegerMap.put(ctx, id);
                    }
                }
                ctx.writeAndFlush(ProxyProtocol.msgProtocol("你好，客户端！" + System.currentTimeMillis()));
            }
        }

        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent) {
                IdleStateEvent event = (IdleStateEvent) evt;
                if (event.state() == IdleState.WRITER_IDLE) {
                    // 写空闲，发送心跳消息
                    ctx.writeAndFlush(ProxyProtocol.heart());
                }
            } else {
                super.userEventTriggered(ctx, evt);
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            // 异常处理
            cause.printStackTrace();
            System.out.println("清理资源");
            integerProxyServerMap.get(contextIntegerMap.get(ctx)).stop();
            integerProxyServerMap.remove(contextIntegerMap.get(ctx));
            contextIntegerMap.remove(ctx);
            ctx.close();
        }

    }

    public void start() {
        try {
            logger.info("启动netty服务");
            run();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }
        new NettyServer().start();
    }
}
